﻿using Engine.Sgml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Engine.Sgml.Configuration;
using Engine.Dtd.Schema;
using System.IO;
using Engine.Sgml.Parser;
using System.Text;
using Engine.Sgml.Validation.Rules;
using System.Xml;
using System.Diagnostics;

namespace Engine.Sgml.Test {


    /// <summary>
    ///This is a test class for SgmlParserTest and is intended
    ///to contain all SgmlParserTest Unit Tests
    ///</summary>
    [TestClass()]
    public class SgmlParserTest {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext {
            get {
                return testContextInstance;
                }
            set {
                testContextInstance = value;
                }
            }

        #region Additional test attributes
        private static SgmlParser parser;
        private static SgmlDocument document;
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext) {
            document = new SgmlDocument();
            document.ValidatorBehavior.DtdDisabled = true;
            ValidationRuleCollection rules = new ValidationRuleCollection(document.Schema.Names);
            rules.Add(ValidationRuleCollection.EmptyRule);
            parser = new Parser.SgmlParser(document, rules);
            }
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        [TestMethod]
        public void TraceSourceTest() {
            document.Root.RemoveElements();
            document.TraceSource.Switch.Level = SourceLevels.All;

            SgmlStream textReader = CreateStream(@"<table style=""border-top:solid 1px #FFFFFF;border-left:solid 1px #FFFFFF;><tr>
    <td colspan=2 style=""border-right:outset 1px #FFFFFF;"">");
            parser.Parse(textReader);
            SElement root = document.Root;
            SElement actual = root.LastNode;
            Assert.AreEqual<string>("table", actual.LocalName);
            Assert.AreEqual<string>("FFFFFF", actual.LastAttribute.Name);
            Assert.AreEqual<string>(actual.LastAttribute.Value, "");
            Assert.IsTrue(actual.Attributes.Count == 4);
            }

        [TestMethod]
        public void ReadCDataSectionTest() {
            DtdSchema schema = DtdSchema.Load(new Uri(@"C:\Documents and Settings\Kir\Рабочий стол\SGML Document\Engine.Sgml.Test\Scheme Samples\Xhtml1-strict.dtd"), "html");
            SgmlDocument document = new SgmlDocument(schema);
            ValidationRuleCollection rules = new ValidationRuleCollection(schema.Names);
            rules.Add(ValidationRuleCollection.EmptyRule);
            SgmlParser parser = new SgmlParser(document, rules);

            document.TraceSource.Switch.Level = SourceLevels.All;

            SgmlStream stream = CreateStream(@"<script id='script'><name><name><name/></name?></script><div id='div'>TEXT</div>");
            parser.Parse(stream);

            SElement script = document.SelectElement(".//script[@id = 'script']");
            Assert.IsNotNull(script);
            SElement div = document.SelectElement(".//div[@id = 'div']");
            Assert.IsNotNull(div);
            }

        [TestMethod]
        public void ReadPInstructionTest() {
            document.Root.RemoveElements();
            SgmlStream stream = CreateStream(@"<?xml version='1.0' encoding='UTF-8' standalone=""yes""?>");
            parser.Parse(stream);

            SElement root = document.Root;
            SElement pi = root.FirstNode;
            Assert.AreEqual<string>(pi.Name, "xml");
            Assert.AreEqual<string>(pi.Value, @"version='1.0' encoding='UTF-8' standalone=""yes""");
            Assert.IsTrue(pi.Attributes.Count == 0);
            }

        [TestMethod]
        public void ReadCharacterDataTest() {
            document.Root.RemoveElements();
            SElement root = document.Root;
            Context context = parser.Context;
            IElementReader reader = context.Readers[SgmlNodeType.CData];
            SgmlStream stream = CreateStream(@"<script>
//<![CDATA[

document.write(&quot;&lt;waka&gt; this is some js generated text.&quot;);

//]]>//
</script>");
            parser.Parse(stream);
            SElement script = document.SelectElement(".//script");
            Assert.IsNotNull(script);
            Assert.IsTrue(script.Nodes.Count == 1);
            Assert.IsTrue(script.FirstNode.NodeType == SgmlNodeType.CData);
            }

        [TestMethod]
        public void ExpandCharacterReferenceTest() {
            document.Root.RemoveElements();
            SElement root = document.Root;
            Context context = parser.Context;

            SgmlStream stream = CreateStream(@"&#x06FA99AAAA<AF");
            parser.Parse(stream);
            SElement actual = document.SelectElement(".//text()");
            Assert.IsNotNull(actual);
            Assert.AreEqual<string>("&99AAAA", actual.Value);

            stream = CreateStream(@"&#116;&#104;&#105;&#115;&#032;&#105;&#115;&#032;&#115;&#111;&#109;&#101;&#032;&#101;&#110;&#099;&#111;&#100;&#101;&#100;&#032;&#116;&#101;&#120;&#116;&#046;");
            parser.Parse(stream);
            actual = actual.NextNode;
            Assert.AreEqual<string>("this is some encoded text.", actual.Value);
            }

        [TestMethod]
        public void ReadStartElementTest() {
            document.Root.RemoveElements();
            SElement root = document.Root;
            Context context = parser.Context;


            SgmlStream textReader = CreateStream(@"<a  onmouseout=""return ttlOut()"" onmousemove=""return ttlOver(event,'<b>Дмитрий Колдун</b>  - победитель телепроекта &quot;Фабрика звезд-6&quot;, финалист международного конкурса &quot;Евровидение 2007&quot;')"" href=""http://r.mail.ru/n43817435"">");
            parser.Parse(textReader);
            SElement actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsTrue(3 == actual.Attributes.Count);

            document.Root.RemoveElements();
            textReader = CreateStream(@"<meta name=""keywords"" content= ""obfuscator, .NET obfuscator, .NET licensing, .NET license, obfuscation, protection, protector, licensing, code encryption, hardware ID"" />");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(2 == actual.Attributes.Count);

            document.Root.RemoveElements();
            textReader = CreateStream(@"<table style=""border-top:solid 1px #FFFFFF;border-left:solid 1px #FFFFFF;><tr>
    <td colspan=2 style=""border-right:outset 1px #FFFFFF;"">");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.AreEqual<string>("table", actual.LocalName);
            Assert.AreEqual<string>("FFFFFF", actual.LastAttribute.Name);
            Assert.AreEqual<string>(actual.LastAttribute.Value, "");
            Assert.IsTrue(actual.Attributes.Count == 4);

            document.Root.RemoveElements();
            textReader = CreateStream(@"<a href=""/search?hl=uk&amp;ie=UTF-8&amp;ei=lNO3TdivDcmgOpKy7cIP&amp;q=.NET+Protection&amp;start=10&amp;sa=N""><img border=""0"" src=""nav_next.gif"" width=""100"" height=""26"" alt=""""><br><strong>Уперед</strong></a>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsTrue(1 == actual.Attribute("href").Value.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Length);

            document.Root.RemoveElements();
            textReader = CreateStream(@"<a href=""http://www.google.com/aclk?sa=l&amp;ai=CWCyPlNO3TbfhDYKNOsbylUXZmspuhYPGxQaXl-PDEBABKANQpP_L0f3_____AWClnqSGmCOgAav10P0DyAEBqgQWT9B3TKt-qKtL9Gjz2vzZOCSHEbAkaQ&amp;num=4&amp;sig=AGiWqtyaBonVxKwoWMliybsGEa-3S1NKhg&amp;adurl=http://www.codewall.net"">Protect .<b>Net</b> Applications</a>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);

            document.Root.RemoveElements();
            textReader = CreateStream(@"<A title="""" style=""className: "" href=""http://www.ibm.com/services/us/iss/html/iss-announcement.html"" target=_self>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attributes("href"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr/>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.IsTrue(actual.IsEmpty);
            Assert.AreEqual<string>(string.Empty, actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr/="">");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.AreEqual<string>(string.Empty, actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr />");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.AreEqual<string>(string.Empty, actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.AreEqual<string>(string.Empty, actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr="""">");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.AreEqual<string>(string.Empty, actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr=/>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.IsFalse(string.IsNullOrWhiteSpace(actual.Attribute("attr")));
            Assert.AreEqual<string>("/", actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr=/path/pat""h/pa<th/a>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.AreEqual<string>("/path/pat\"h/pa<th/a", actual.Attribute("attr"));

            document.Root.RemoveElements();
            textReader = CreateStream(@"<tag attr=/path/pat""h/p""ath/a</div>");
            parser.Parse(textReader);
            actual = root.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Element);
            Assert.IsNotNull(actual.Attribute("attr"));
            Assert.AreEqual<string>("/path/pat\"h/p\"ath/a", actual.Attribute("attr"));
            }

        private SgmlStream CreateStream(string literal) {
            return new SgmlStream(new MemoryStream(Encoding.UTF8.GetBytes(literal)), Encoding.UTF8);
            }


        /// <summary>
        ///A test for ReadComment
        ///</summary>
        [TestMethod()]
        public void ReadCommentTest() {
            document.DocumentType = SgmlDocumentType.Html;
            document.Root.RemoveElements();
            SElement root = document.Root;
            Context context = parser.Context;
            Parser.SgmlParser target = parser;

            SgmlStream stream = CreateStream("<!-- - Comment -- Com- -me--nt-- -->");
            string vlaue = " - Comment  Com- -ment ";
            target.Parse(stream);
            SElement actual = root.FirstNode.LastNode;

            Assert.IsNotNull(actual);
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream(@"<!--[if IE]>
<style type=""text/css""> 
/* place css fixes for all versions of IE in this conditional comment */
.thrColLiqHdr #sidebar2, .thrColLiqHdr #sidebar1 { padding-top: 0px; }
.thrColLiqHdr #mainContent { zoom: 1; padding-top: 0px; }
/* the above proprietary zoom property gives IE the hasLayout it needs to avoid several bugs */
</style>
<![endif]-->");
            document.Root.RemoveElements();
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsNotNull(actual);
            Assert.IsTrue(root.FirstNode.Nodes.Count == 1);
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);


            stream = CreateStream("<!-- Hello --->");
            vlaue = " Hello ";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!-- . -- >");
            vlaue = " .  ";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!>");
            vlaue = "";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!-- Hello -->");
            vlaue = " Hello ";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!-- Hello -- -- Hello-->");
            vlaue = " Hello   Hello";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!---->");
            vlaue = "";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!------ Hello -->");
            vlaue = " Hello ";
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            stream = CreateStream("<!------> hello-->");
            vlaue = "";
            target.Parse(stream);
            actual = root.FirstNode.LastNode.PreviousNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            document.Root.RemoveElements();
            stream = CreateStream(@"<!-- language=""Javascript"" src=""http:\//www.icodeasp.com/code.js""><xx/script><!-- language=""Javascript"">GetReferrer(1103)<xx/script>
");
            vlaue = @" language=""Javascript"" src=""http:\//www.icodeasp.com/code.js""";
            target.Parse(stream);

            actual = root.FirstNode.FirstNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            Assert.AreEqual(vlaue, actual.Value);

            SElement xx = root.SelectElement(".//xx");
            Assert.IsNotNull(xx);
            actual = xx.FirstNode;
            Assert.IsNotNull(actual);
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);


            stream = CreateStream(@"<!-- Code for :bbc----->");
            target.Parse(stream);
            actual = root.FirstNode.LastNode;
            Assert.IsTrue(actual.NodeType == SgmlNodeType.Comment);
            }
        }
    }
